iT邦幫忙

2026 iThome 鐵人賽

DAY 26
0
Claude AI

Claude × Playwright:從新進同事到 Agentic SDET 代理人系列 第 26 篇

第 26 天|替購物車寫支自動化測試

  • 分享至 

  • xImage
  •  

前言

昨天,我們用一支回歸測試抓住產品缺陷,再確認修復有效。既然測試能幫忙守住修好的地方,接下來也可以把前面探索過的重要行為,交給它定期檢查。

今天就從購物車開始:每列金額應該等於單價乘以數量。這句話很短,卻能抓到我們先前遇過的問題:每列都顯示 $00.00,頁尾總計卻是對的。帳算對了,明細像是在請客。

開始之前

寫測試之前,我們先確認它值得留下來。前幾天已經完成探索、盲驗和開單檢查,現在知道正確行為是什麼,也有證據可對照,才適合把它寫成固定檢查。

如果順序反過來,先請助手生一大批測試,之後可能得花更多時間確認它們到底在驗什麼。測試會跑、會通過,還不代表它問對了問題。開始前也要沿用前面備好的產品設定,讓助手知道受測網址、登入方式和測試目錄;缺了就先補齊。

因此,今天的 test-author(撰寫測試)要由你主動呼叫。多一支測試,往後就多一支要維護;助手可以幫忙寫,該不該新增仍由我們決定。

動手試試

在配套專案 sdet-skills/ 開啟助手對話,確認已安裝本書使用的技能,再貼上這段提示詞:

/sdet-skills:test-author 請把購物車的「每列金額=單價×數量」寫成自動化測試。
先讀既有問題證據、測試風格設定與共用操作,確認正確行為。
先查有沒有同樣的測試;有就沿用並檢查,不要再新增一支。
完成後分別跑乾淨版與含缺陷版,交回測試檔、結果和失敗證據。

這段適合接著前面的對話使用。如果換了對話,助手不知道證據放在哪裡,我們就補上位置。以下路徑以 sdet-skills/ 為起點,對應本篇配套檔案;歷史問題報告若不在你的副本裡,要換成自己保存的證據:

問題證據:output/reports/issues/2026-07-30-cart-line-total-zero.md
測試風格範本:config/test-style.example.md
預設測試原則:references/test-design.md
共用操作:tests/fixtures/sut.ts
購物車測試:tests/e2e/cart-line-total.spec.ts
執行設定:tests/playwright.config.ts

拿到檔案後,助手會先查頁面提供哪些定位方式,再寫斷言。你也可以在終端機手動執行整套示範測試:

npm run test:clean
npm run test:with-bugs

這兩行要在 sdet-skills/ 執行。它們用同一份測試碼,透過 SUT 環境變數切換 Toolshop 的兩個公開版本:clean 是乾淨版,with-bugs 是刻意植入缺陷的版本。這和昨天修產品時使用的本機環境,是不同批實驗。

跑完之後

整套示範共有四支測試:兩支驗登入,兩支驗購物車。其中一支購物車測試長這樣,共用操作都放在 tests/fixtures/sut.ts:

test('購物車每一列的 Total 應該等於單價乘以數量', async ({ page }) => {
  const { name, price } = await openFirstProduct(page)
  await addToCart(page)
  await gotoCart(page)

  const row = page.locator('tbody tr').filter({ hasText: name }).first()
  const qty = Number(await row.locator('[data-test="product-quantity"]').inputValue())
  const unit = money(await row.locator('[data-test="product-price"]').innerText())
  const line = money(await row.locator('[data-test="line-price"]').innerText())

  expect.soft(unit, '商品頁與購物車的單價應該一致').toBeCloseTo(price, 2)
  expect(line, `${name}:${unit} × ${qty} 應該等於列總計(SUT=${SUT})`).toBeCloseTo(unit * qty, 2)
})

它從頁面讀取商品、單價和數量,再核對列金額,所以商品換了,也不必跟著改一堆寫死的數字。當時整套跑完,結果如下:

SUT=clean        4 passed
SUT=with-bugs    2 passed, 2 failed

另一支購物車測試負責比對「各列金額加總」與「頁尾總計」,留下這段訊息:

Error: 列總計相加 0 應該等於頁尾 14.15(SUT=with-bugs)
Expected: 14.15
Received: 0

同一份測試跑兩個版本:乾淨版四支通過,含缺陷版兩支通過、兩支失敗

看到這裡,我們才把結果和先前證據放在一起看。這次頁面正常載入,失敗的金額也與探索、盲驗發現的問題一致,因此支持產品有缺陷的判斷。光是一邊紅、一邊綠,還不能定案;明後天就會遇到其他原因造成的紅燈。

失敗訊息也值得多看一眼。接手的人不用先翻程式,就知道在哪個版本、哪筆金額不對。這樣他收到報告時,才能接著查,而不是先問你「所以到底壞在哪?」

背後怎麼做

既然要讓別人接得下去,寫法就得有幾個共同習慣。我們用下面五條檢查:

寫法 為什麼這樣做
一支測試驗一個行為 失敗時容易縮小範圍,不把登入到結帳全塞在一起
名稱寫出使用者期待的結果 「列金額應等於單價乘數量」比「點擊按鈕」有用
先找測試專用屬性,再看角色與文字 避免依賴容易變動的版面位置
等到條件成立才往下走 不用固定睡幾秒賭畫面已經好了
從頁面或測資取得會變動的值 不把商品名、價格和編號寫死

定位方式可以先用 tests/tools/probe-selectors.ts 探查;本篇的 data-test 名稱就是查過才用。至於等待,Playwright 的網頁斷言能反覆檢查條件,但上面讀成數字後使用的 toBeCloseTo 不會重新讀頁面,所以讀值前仍須確認畫面已就緒。兩者要分清楚。斷言的官方說明

資料和帳密也要一起處理。需要固定測資時,先建立帶有唯一標記的資料,用完只清自己的部分;帳密則放環境變數。本專案缺少登入帳密就會跳過相關測試,報告必須明講跳過幾支,不能把「沒驗」算成「通過」。

寫完後,我們再做一次交付檢查:失敗訊息看得懂嗎?測資會自行準備、清理嗎?測試是否依賴執行順序,或與現有項目重複?最後,故意把預期值改錯,確認測試真的會失敗,再還原。

最後這招只是在確認斷言有執行。還原後,乾淨版應該通過;已知有缺陷的版本仍可能失敗,別為了湊一片綠色又把答案改回錯的。

至於命名、導頁方式等慣例,先讀專案的測試風格設定。現行技能使用 config/<project>/test-style.md,例如 config/toolshop/test-style.md;可以參考配套範本建立,沒有設定時則沿用 references/test-design.md。縮排和引號交給格式檢查工具就好。

今天學到什麼

今天,我們把已確認的購物車問題變成固定檢查,並用兩個版本對照結果。測試留下來之前,還要確認它驗對行為、沒有重複,也能讓接手的人看懂失敗原因。

不過,再好的測試,忘記跑也不會提醒你。明天就把它接進 GitHub Actions,讓相關程式碼更新時自動執行,連報告和證據一起留下。


上一篇
Day 25|第一次修程式,才發現原本的測試也錯了
下一篇
Day 27|本機測試都通過了,放到 CI 卻失敗
系列文
Claude × Playwright:從新進同事到 Agentic SDET 代理人 共 28 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言